package cn.com.zetatech.loader.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.function.Predicate;

@Slf4j
public class FileUtils {

    /**
     * 文件是否处于更新中
     */
    public static Boolean isFileUpdating(File file) {
        long lastModified = file.lastModified();
        try {
            Thread.sleep(200L);
        } catch (InterruptedException e) {

        }
        return file.lastModified() > lastModified;
    }

    public static List<String> getFileNameList(String path, Predicate<String> filter, boolean workTree) {
        if (workTree) {
            return getFileNameList(path, filter);
        }
        File file = new File(path);
        List<String> fileList = new ArrayList<>();
        File[] files = file.listFiles((dir, name) -> filter.test(name));
        if (files != null) {
            for (File file1 : files) {
                fileList.add(file1.getName());
            }
        }
        return fileList;
    }


    public static List<String> getFileNameList(String path, Predicate<String> filter) {
        List<String> fileList = new ArrayList<>();
        try {
            Path startingDir = Paths.get(path);
            Files.walkFileTree(startingDir, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                    if (filter.test(file.getFileName().toString())) {
                        fileList.add(file.getFileName().toString());
                    }
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) {
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileList;
    }


    public static List<String> getFileList(String path, Predicate<String> filter) throws IOException {
        log.info("开始遍历文件夹：{}", path);
        List<String> fileList = new ArrayList<>();
        Path startingDir = Paths.get(path);
        Files.walkFileTree(startingDir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (filter.test(file.getFileName().toString())) {
                    fileList.add(file.toString());
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {
                return FileVisitResult.CONTINUE;
            }
        });
        return fileList;
    }


    public static String getFileNameNoSuffix(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return "";
        }

        return fileName.substring(0, fileName.lastIndexOf("."));
    }


    /**
     * 递归遍历目录以及子目录中的所有文件<br>
     * 如果提供path为文件，直接返回过滤结果
     *
     * @param path       当前遍历文件或目录
     * @param maxDepth   遍历最大深度，-1表示遍历到没有目录为止
     * @param fileFilter 文件过滤规则对象，选择要保留的文件，只对文件有效，不过滤目录，null表示接收全部文件
     * @return 文件列表
     * @since 5.4.1
     */
    public static List<File> loopFiles(Path path, int maxDepth, FileFilter fileFilter) throws IOException {
        final List<File> fileList = new ArrayList<>();

        if (null == path || !Files.exists(path)) {
            return fileList;
        } else if (!Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) {
            final File file = path.toFile();
            if (null == fileFilter || fileFilter.accept(file)) {
                fileList.add(file);
            }
            return fileList;
        }

        walkFiles(path, maxDepth, new SimpleFileVisitor<Path>() {

            @Override
            public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
                final File file = path.toFile();
                if (null == fileFilter || fileFilter.accept(file)) {
                    fileList.add(file);
                }
                return FileVisitResult.CONTINUE;
            }
        });

        return fileList;
    }

    public static void walkFiles(Path start, int maxDepth, FileVisitor<? super Path> visitor) throws IOException {
        if (maxDepth < 0) {
            // < 0 表示遍历到最底层
            maxDepth = Integer.MAX_VALUE;
        }
        Files.walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), maxDepth, visitor);
    }

}
